home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Scene 96
/
Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso
/
misc
/
coding
/
pump_src
/
phong.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-10-26
|
14KB
|
450 lines
//──────────────────────────────────────────────────────────────────────────
// Implementación del engine Phong/EnvMapping, Yann/Iguana
//──────────────────────────────────────────────────────────────────────────
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sincos.h>
#include <vga.h>
#include "phong.h"
#include "ph_fill.h"
extern int tracing;
#define TRACE(r,g,b) do { if (tracing) VGA_PutColor(0,r,g,b); } while(0)
void *frame_buffer_adr = (void *)0xA0000;
#define MAX_OBJECTS 5
#define VERY_CLOSE 10
#define BACKFACE_CULL
struct O3DHeader {
UWORD m_num_vertices;
UWORD m_num_triangles;
};
static struct CGlobalTri {
UWORD m_num_obj; // En qué objeto está el triangulo
UWORD m_num_tri; // Qué triángulo dentro del objeto
UWORD m_distance; // Distancia a la que está el tri.
struct CGlobalTri *m_next; // Link
};
static struct CObject {
struct CPoint *m_vertices;
struct CNormal *m_normals;
struct CTriangle *m_triangles;
struct CPoint *m_xvertices;
struct CPoint2D *m_proj_vertices;
struct CNormal *m_xnormals;
UWORD m_num_obj; // Identificador de objeto **//**
UWORD m_num_vertices, m_num_triangles;
BOOL m_all_ok;
BOOL m_active;
} s_objects[MAX_OBJECTS];
static int s_num_objects = 0; // Cuántos son -^
static struct CGlobalTri *s_list = 0; // Lista global de triángulos
static struct CGlobalTri *s_pool = 0, *s_next = 0; // Pool para no hacer mallocs
static struct CGlobalTri *GetTri(void) { // Acceso al pool
return s_next++;
}
static void RestartPool(void) { // Inicializar la pool
s_next = s_pool;
}
void PH_SetMode13BufferAdr(void *p) {
frame_buffer_adr = p;
}
void *PH_GetMode13BufferAdr(void) {
return frame_buffer_adr;
}
static struct CObject *NewObject(void) {
struct CObject *p = s_objects + s_num_objects;
if (s_num_objects == MAX_OBJECTS) {
puts("ORRRROOOOORRRRRRRRR!!!!!!!!!!!!!");
exit(-1);
}
p->m_num_obj = s_num_objects++;
return p;
}
static void ReserveMem(struct CObject *p) {
p->m_all_ok = FALSE;
p->m_xvertices = calloc(p->m_num_vertices, sizeof(struct CPoint));
if (!p->m_xvertices)
return;
p->m_xnormals = calloc(p->m_num_vertices, sizeof(struct CNormal));
if (!p->m_xnormals) {
free(p->m_xvertices);
return;
}
p->m_proj_vertices = calloc(p->m_num_vertices, sizeof(struct CPoint2D));
if (!p->m_proj_vertices) {
free(p->m_xvertices);
free(p->m_xnormals);
return;
}
p->m_vertices = calloc(p->m_num_vertices, sizeof(struct CPoint));
if (!p->m_vertices) {
free(p->m_xvertices);
free(p->m_xnormals);
free(p->m_proj_vertices);
return;
}
p->m_normals = calloc(p->m_num_vertices, sizeof(struct CNormal));
if (!p->m_normals) {
free(p->m_xvertices);
free(p->m_xnormals);
free(p->m_proj_vertices);
free(p->m_vertices);
return;
}
p->m_triangles = calloc(p->m_num_triangles, sizeof(struct CTriangle));
if (!p->m_triangles) {
free(p->m_xvertices);
free(p->m_xnormals);
free(p->m_proj_vertices);
free(p->m_vertices);
free(p->m_normals);
return;
}
p->m_all_ok = TRUE;
}
HANDLE PH_BuildObj(BYTE *file_like_buffer) {
struct O3DHeader hdr;
struct CObject *p = NewObject();
char *q = (char *)file_like_buffer;
p->m_all_ok = FALSE;
memcpy(&hdr, q, sizeof(struct O3DHeader));
q += sizeof(struct O3DHeader);
// Reservar memoria
p->m_num_vertices = hdr.m_num_vertices;
p->m_num_triangles = hdr.m_num_triangles;
ReserveMem(p);
if (!p->m_all_ok) {
return 0;
}
// Leer los datos
memcpy(p->m_vertices, q, p->m_num_vertices * sizeof(struct CPoint));
q += p->m_num_vertices * sizeof(struct CPoint);
memcpy(p->m_normals, q, p->m_num_vertices * sizeof(struct CNormal));
q += p->m_num_vertices * sizeof(struct CNormal);
memcpy(p->m_triangles, q, p->m_num_triangles * sizeof(struct CTriangle));
q += p->m_num_triangles * sizeof(struct CTriangle);
p->m_all_ok = TRUE;
p->m_active = TRUE;
return p - s_objects + 1;
}
void PH_DestroyObj(HANDLE h) {
struct CObject *p = s_objects + h + 1;
if (!p->m_all_ok)
return;
if (p->m_xvertices) free(p->m_xvertices);
if (p->m_xnormals) free(p->m_xnormals);
if (p->m_vertices) free(p->m_vertices);
if (p->m_normals) free(p->m_normals);
if (p->m_triangles) free(p->m_triangles);
if (p->m_proj_vertices) free(p->m_proj_vertices);
s_num_objects--; // Llevar la cuenta (para automatizar más
// tarde algunas cosillas)
}
int PH_StartEngine(void) {
// Se supone que ya se han construido todos los objetos.
// Vamos a reservar la memoria que hace falta para todo el render
int i;
UWORD total_tris = 0;
for (i = 0; i < s_num_objects; i++) {
total_tris += s_objects[i].m_num_triangles;
}
if (!total_tris)
return TRUE; // No hay objetos!
s_pool = calloc(total_tris, sizeof(struct CGlobalTri));
if (!s_pool)
return 0; // No hay memoria
RestartPool();
return 1;
}
void PH_EndEngine(void) {
free(s_pool);
}
static void ProjectVertices(struct CObject *pobj) {
int i;
struct CPoint *p = pobj->m_xvertices;
struct CPoint2D *q = pobj->m_proj_vertices;
for (i = 0; i < pobj->m_num_vertices; i++, p++, q++) {
if (p->z < VERY_CLOSE) {
q->x = 0;
q->y = 0;
continue;
}
q->x = (((DWORD)p->x << 8) / p->z) + 160;
q->y = (((DWORD)p->y << 8) / p->z) + 100;
}
}
static void DumpPolygons(struct CObject *p) {
int i;
struct CTriangle *pt = p->m_triangles;
struct CPoint *pp1, *pp2, *pp3;
// Añadir todos los triángulos del objeto actual a la lista global,
// haciendo un sencillo clipping accept/reject
for (i = 0; i < p->m_num_triangles; i++, pt++) {
struct CGlobalTri *pgtri;
pp1 = p->m_xvertices + pt->p1;
pp2 = p->m_xvertices + pt->p2;
pp3 = p->m_xvertices + pt->p3;
if (pp1->z < VERY_CLOSE || pp2->z < VERY_CLOSE || pp3->z < VERY_CLOSE)
continue;
pgtri = GetTri();
pgtri->m_num_obj = p->m_num_obj;
pgtri->m_num_tri = i;
pgtri->m_distance = pp1->z + pp2->z + pp3->z;
pgtri->m_next = s_list;
s_list = pgtri;
}
}
void PH_DrawFrame(void) {
int i;
struct CGlobalTri *trav;
// Comenzamos un render
RestartPool();
s_list = NULL;
TRACE(32,32,0);
// Llamar a ProjectVertices y DumpPolygons para todos los polígonos
for (i = 0; i < s_num_objects; i++) {
if (s_objects[i].m_active) {
ProjectVertices(s_objects + i);
DumpPolygons(s_objects + i);
}
}
// Ordenar los triángulos de todos los objetos
TRACE(16,16,16);
SortTris();
// Dibujarlos todos con ph_fill, haciendo backface-culling
for (trav = s_list; trav; trav = trav->m_next) {
BYTE z_val[3];
struct CObject *pobj = s_objects + trav->m_num_obj;
struct CTriangle *pt = pobj->m_triangles + trav->m_num_tri;
TRACE(0,0,16);
ex1 = pobj->m_proj_vertices[pt->p1].x;
ey1 = pobj->m_proj_vertices[pt->p1].y;
ex2 = pobj->m_proj_vertices[pt->p2].x;
ey2 = pobj->m_proj_vertices[pt->p2].y;
ex3 = pobj->m_proj_vertices[pt->p3].x;
ey3 = pobj->m_proj_vertices[pt->p3].y;
#ifdef BACKFACE_CULL
if ((ex2-ex1)*(ey3-ey2)-(ey2-ey1)*(ex3-ex2) < 0) {
continue;
}
#endif
z_val[0] = pobj->m_xnormals[pt->p1].z;
z_val[1] = pobj->m_xnormals[pt->p2].z;
z_val[2] = pobj->m_xnormals[pt->p3].z;
if (z_val[0] <= 0 && z_val[1] <= 0 && z_val[2] <= 0) {
u1 = v1 = u2 = v2 = u3 = v3 = 0;
} else {
u1 = ((WORD)pobj->m_xnormals[pt->p1].x << 8) + 0x8000;
v1 = ((WORD)pobj->m_xnormals[pt->p1].y << 8) + 0x8000;
u2 = ((WORD)pobj->m_xnormals[pt->p2].x << 8) + 0x8000;
v2 = ((WORD)pobj->m_xnormals[pt->p2].y << 8) + 0x8000;
u3 = ((WORD)pobj->m_xnormals[pt->p3].x << 8) + 0x8000;
v3 = ((WORD)pobj->m_xnormals[pt->p3].y << 8) + 0x8000;
}
TRACE(40,40,40);
phong_fill();
}
}
/////////////////////////////////////////////////////////////////////////////
// Ordena la lista s_list, utilizando el método RADIX-SORT con raíz 16,
// por lo que hacen falta 4 pasadas
/////////////////////////////////////////////////////////////////////////////
#if 1
#define RADIX 16
#define PASSES 4
#define EXTRACT(num, pass) \
((num >> (pass << 2)) & (RADIX-1))
#else
#define RADIX 256
#define PASSES 2
#define EXTRACT(num, pass) \
((num >> (pass << 3)) & (RADIX-1))
#endif
static void SortTris(void) {
WORD i, j;
struct CGlobalTri *heads[RADIX], *head, **tails[RADIX], **tail,
*trav, *temp_next;
// Ordenar la lista de triángulos global
head = s_list;
for (i = 0; i < PASSES; i++) {
// Inicializar tails
for (j = 0; j < RADIX; j++) {
tails[j] = heads + j;
}
// Recorrer la lista principal y separar en RADIX listas
for (trav = head; trav; trav = temp_next) {
int k;
temp_next = trav->m_next;
k = EXTRACT(trav->m_distance, i);
*tails[k] = trav;
tails[k] = &trav->m_next;
}
// Terminar las listas
for (j = 0; j < RADIX; j++) {
*tails[j] = NULL;
}
// Añadir las listas a la lista principal
head = NULL;
tail = &head;
//for (j = 0; j < RADIX; j++) { // Orden creciente
for (j = RADIX - 1; j >= 0; j--) { // Orden decreciente
if (heads[j]) {
// Añadir la lista número 'j' al final
*tail = heads[j];
tail = tails[j];
}
}
}
s_list = head;
}
void PH_XFormVertices(HANDLE h, UWORD theta, UWORD phi, WORD x, WORD y, WORD z) {
int i;
DWORD cos_theta = Cos(theta);
DWORD sin_theta = -Sin(theta);
DWORD cos_phi = Cos(phi);
DWORD sin_phi = Sin(phi);
DWORD sinphi_sintheta = FPMult(sin_phi, sin_theta);
DWORD sinphi_costheta = FPMult(sin_phi, cos_theta);
DWORD cosphi_sintheta = FPMult(cos_phi, sin_theta);
DWORD cosphi_costheta = FPMult(cos_phi, cos_theta);
struct CPoint *p;
struct CPoint *q;
struct CObject *pobj = s_objects + h - 1;
for (i = 0, p = pobj->m_vertices, q = pobj->m_xvertices ;
i < pobj->m_num_vertices;
i++, p++, q++) {
/*
q->x = x + FPMult(p->x, cos_theta) + FPMult(p->z, sin_theta);
q->y = y + p->y;
q->z = z + FPMult(p->z, cos_theta) - FPMult(p->x, sin_theta);
*/
q->x = x + FPMult(p->x, cos_theta) + FPMult(p->z, sin_theta);
q->y = y - FPMult(p->x, sinphi_sintheta)
+ FPMult(p->y, cos_phi)
+ FPMult(p->z, sinphi_costheta);
q->z = z - FPMult(p->x, cosphi_sintheta)
- FPMult(p->y, sin_phi)
+ FPMult(p->z, cosphi_costheta);
}
}
#define NONE 8
static int repr[] =
{ 2, 3, NONE, NONE, NONE, 4, NONE, 5, 1, NONE, 0, NONE, NONE, NONE, 7, 6 };
static BYTE u_repr[] =
{ 127, 90, 0, -90, -127, -90, 0, 90, 0}; // Last is for NONE
static BYTE v_repr[] =
{ 0, 90, 127, 90, 0, -90, -127, -90, 0};
void PH_XFormNormals(HANDLE h, WORD theta, UWORD phi, WORD alpha) {
int i;
DWORD cos_theta, sin_theta, cos_phi, sin_phi;
DWORD sinphi_sintheta;
DWORD sinphi_costheta;
DWORD cosphi_sintheta;
DWORD cosphi_costheta;
struct CObject *pobj = s_objects + h - 1;
struct CNormal *r = pobj->m_normals;
struct CNormal *s = pobj->m_xnormals;
theta += alpha;
cos_theta = Cos(theta);
sin_theta = -Sin(theta);
cos_phi = Cos(phi);
sin_phi = Sin(phi);
sinphi_sintheta = FPMult(sin_phi, sin_theta);
sinphi_costheta = FPMult(sin_phi, cos_theta);
cosphi_sintheta = FPMult(cos_phi, sin_theta);
cosphi_costheta = FPMult(cos_phi, cos_theta);
// Xform normals
for (i = 0; i < pobj->m_num_vertices; i++) {
/*
s->x = FPMult(cos_sum, r->x) + FPMult(sin_sum, r->z);
s->y = r->y;
s->z = FPMult(cos_sum, r->z) - FPMult(sin_sum, r->x);
*/
s->x = FPMult(r->x, cos_theta) + FPMult(r->z, sin_theta);
s->y = - FPMult(r->x, sinphi_sintheta)
+ FPMult(r->y, cos_phi)
+ FPMult(r->z, sinphi_costheta);
s->z = - FPMult(r->x, cosphi_sintheta)
- FPMult(r->y, sin_phi)
+ FPMult(r->z, cosphi_costheta);
if (s->z <= 0) {
WORD u, v, code;
u = s->x; v = s->y;
code = (((UWORD)(v - (u<<1))) >> 15) << 3
| (((UWORD)(u + (v<<1))) >> 15) << 2
| (((UWORD)((v<<1) - u)) >> 15) << 1
| (((UWORD)(v + (u<<1))) >> 15);
s->x = u_repr[repr[code]];
s->y = v_repr[repr[code]];
}
s++, r++;
}
}
void PH_ActivateObj(HANDLE h, int active) {
struct CObject *pobj = s_objects + h - 1;
pobj->m_active = active;
}